﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Collections.Concurrent;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.IO;
using System.Web.Script.Serialization;
using System.Timers;
using System.Runtime.Serialization.Formatters.Binary;
using System.Runtime.Serialization.Json;
using System.Linq;
using DataType.MessageType;

namespace WargameForDistribution
{
    public class UdpServer : IDisposable
    {
        /// <summary>
        /// </summary>
        /// <remarks>
        ///     UDP数据包的理论最大长度限制是 65535 bytes，这包含 8 bytes 数据包头和 65527 bytes 数据。但如果基于IPv4网络传输，则还需减去 20 bytes 的IP数据包头。
        ///     则单一的UDP数据包可传输的数据最大长度为：
        ///     MaxUdpDataLength = 65535 - 8 - 20 = 65507 bytes
        ///     这就需要实现UDP包的分包传输和接收组包功能。
        /// </remarks>
        /// 
        private static List<ActionMsg> actions = new List<ActionMsg>();
        private readonly ManualResetEvent m_ReceiveDone = new ManualResetEvent(false);
        private readonly ManualResetEvent m_SendDone = new ManualResetEvent(false);
        private readonly IPEndPoint m_LocalSendEp;
        private IPEndPoint m_LocalRecvEp;
        private IPEndPoint m_LocalRecvEp_1;
        private bool m_IsRunning;
        private bool isfirst;
        private Thread m_ReceiveThread;
        private Thread m_SendThread;
        private UdpClient m_UdpReceive;
        private UdpClient m_UdpReceive_1;
        private UdpClient m_UdpSend;
        private static System.Timers.Timer aTimer;
        private List<IPEndPoint> IP_red { get; set; }
        private List<IPEndPoint> IP_blue { get; set; }
        bool red_ok = false;
        bool blue_ok = false;
        public UdpServer(string ip, int port)
        {

            IPAddress ipAddress;
            if (!IPAddress.TryParse(ip, out ipAddress))
            {
                throw new Exception("ip is not valid ip address");
            }

            this.m_LocalSendEp = new IPEndPoint(IPAddress.Any, port);
            this.m_LocalRecvEp = new IPEndPoint(IPAddress.Any, port + Consts.RecvPortInterval);
            this.m_LocalRecvEp_1 = new IPEndPoint(IPAddress.Any, port + Consts.RecvPortInterval * 2);
            this.m_IsRunning = false;
            isfirst = true;
        }
        #region Implementation of IDisposable

        /// <summary>
        ///     执行与释放或重置非托管资源相关的应用程序定义的任务。
        /// </summary>
        public void Dispose()
        {
            if (this.m_ReceiveThread.IsAlive)
            {
                this.m_ReceiveThread.Abort();
            }

            if (this.m_SendThread.IsAlive)
            {
                this.m_SendThread.Abort();
            }

            this.m_IsRunning = false;

            this.m_UdpSend?.Close();
            this.m_UdpReceive?.Close();
        }
        #endregion
        public void Start()
        {
            SetTimer();         // 用来Step和发送态势的  没有aTimer.Enabled = true;即没有start启动     默认自动在线程池中分配线程运行     在ReceiveMessages的ParseReceivedData中启动了，接收的actions动作后开始Step和发送态势
            IP_red = new List<IPEndPoint>();
            IP_blue = new List<IPEndPoint>();
            if (!this.m_IsRunning)
            {
                this.m_IsRunning = true;

                this.m_UdpReceive = new UdpClient(this.m_LocalRecvEp);      //  UdpClient 省略了插口Socket定义（构造方法中用m_LocalRecvEp定义了），省略了绑定bind上插口（在构造方法中）（bind绑定IP和端口是为了能接收数据），，，多了connect方法（目前没使用）
                m_UdpReceive_1 = new UdpClient(m_LocalRecvEp_1);
                this.m_UdpSend = new UdpClient(this.m_LocalSendEp);

                if (this.m_ReceiveThread == null || this.m_ReceiveThread.ThreadState == ThreadState.Stopped)
                {
                    this.m_ReceiveThread = new Thread(this.ReceiveMessages);
                    this.m_ReceiveThread.Start();
                }

                if (this.m_SendThread == null || this.m_SendThread.ThreadState == ThreadState.Stopped)
                {
                    this.m_SendThread = new Thread(this.SendMessages);
                    //this.m_SendThread.Start();                            ///////////不start启动线程
                }
            }
        }
        private void SetTimer()
        {
            // Create a timer with a two second interval.
            aTimer = new System.Timers.Timer(100);
            // Hook up the Elapsed event for the timer. 
            aTimer.Elapsed += OnTimedEvent;
            aTimer.AutoReset = true;
            //if (red_ok == true || blue_ok == true)
            // aTimer.Enabled = true;

        }
        private void OnTimedEvent(Object source, ElapsedEventArgs e)
        {
            if (isfirst == true)//第一次推演,发送setup之后的初始态势
            {
                isfirst = false;
                this.Send(DataFactory.game.FullObservation);
            }
            //Consts.game.Step(Consts.game.CurObservation);
            // Wargame.
            //在step之前，先把上一次推演出的态势CurObservation（-1, 红0, 蓝1)和done发送给客户端
            //game.Step(actions); 
            else
            {
                if (DataFactory.game.Done) return;
                DataFactory.game.Step(actions);
                //保存推演出的态势CurObservation（-1, 红0, 蓝1)和done发送给客户端，
                this.Send(DataFactory.game.FullObservation);
            }
            //推演一次完成后，要清空actions列表
        }
        #region 新的代码，改进的地方是不用死循环进行接受处理，而是采用一次结束后继续接受的方式

        public void ReceiveMessages()
        {
            if (this.m_IsRunning)
            {
                this.m_ReceiveDone.Reset();      //  无信号状态

                this.m_UdpReceive.BeginReceive(this.ReceiveCallback, this.m_UdpReceive);        //  此语句不会中断程序

                this.m_UdpReceive_1.BeginReceive(this.ReceiveCallback, this.m_UdpReceive_1);

                this.m_ReceiveDone.WaitOne();    //  阻塞
            }

            if (!this.m_IsRunning)
            {
                this.m_UdpReceive.Close();
                this.m_UdpReceive_1.Close();
                this.m_LocalRecvEp = null;
            }
        }

        public void ReceiveCallback(IAsyncResult result)    // result 包含 m_UdpReceive          result.AsyncState是m_UdpReceive
        {
            if (result == null)
            {
                this.m_ReceiveDone.Set();       //  解除阻塞
                return;
            }

            if (result.IsCompleted)
            {
                var udpState = (UdpClient)result.AsyncState;
                if (udpState?.Client != null /*&& udpState.Client.Connected*/)       //  Client就是插口Socket
                {
                    try
                    {
                        var remoteEp = new IPEndPoint(Dns.GetHostAddresses(Dns.GetHostName())[0], 0);    // 接收 当前主机的第一个IP地址，当前主机的任意接口port  的信息   （定义了接收范围）
                        var receiveBytes = udpState.EndReceive(result, ref remoteEp);               //  ref是引用  推测是修改了remoteEp为发送端的IP、port

                        // 接收和发送的约定，接收的port=发送的port+100
                        //remoteEp.Port = remoteEp.Port +Consts.RecvPortInterval;

                        this.ParseReceivedData(receiveBytes, remoteEp);
                        this.m_ReceiveDone.Set();

                        // 可能不需要了
                        //Thread.Sleep(100);

                        // 接受完后，继续监听
                        if (DataFactory.game.Done) m_IsRunning = false;
                        this.ReceiveMessages();     //调上一个方法，，来循环执行
                    }
                    catch (Exception)
                    {
                    }
                }
            }
        }

        #endregion
        private void ParseReceivedData(byte[] datagram, IPEndPoint remoteEp)
        {
            try
            {
                var receivestring = Encoding.Default.GetString(datagram);
                if (receivestring.Substring(0, 3) == "beg")
                {
                    isfirst = false;
                    this.Send(DataFactory.game.FullObservation);
                }
                if (receivestring.Substring(0, 3) == "act")
                {
                    receivestring = receivestring.Replace("act", "");

                    actions = Utils.Parse(receivestring);
                    //启动定时器，每一秒启动一次，进行推演
                    aTimer.Enabled = true;
                }

                else if (receivestring.Substring(0, 3) == "red")        //  红方给服务器发了red，服务器记录IP和port为红方的，然后给红方发OK
                {
                    IP_red.Add(remoteEp);
                    Send("ok", IP_red);
                    red_ok = true;

                }
                else if (receivestring.Substring(0, 3) == "blu")
                {
                    IP_blue.Add(remoteEp);
                    Send("ok", IP_blue);
                    blue_ok = true;
                }


            }
            catch (Exception ex)
            {
                var cc = ex.InnerException.Message;

                Console.Out.WriteLine(cc);
                //RaiseCmdExceptionEvent(ex.Message);
            }
        }
        #region 发送当前态势
        private void SendMessages()
        {

            {
                this.Send(DataFactory.game.FullObservation);
            }
            Thread.Sleep(100);
        }
        protected void Send(Dictionary<int, ObservationMsg> curObservation)
        {
            if (!red_ok || !blue_ok) return;

            ObservationMsg obe = new ObservationMsg();

            foreach (int key in curObservation.Keys)
            {
                if (key == 0 && red_ok == true)
                {
                    obe.actions = curObservation[key].actions; //发送给红方
                    obe.cities = curObservation[key].cities;
                    obe.judge_info = curObservation[key].judge_info;
                    obe.operators = curObservation[key].operators;
                    obe.valid_actions = curObservation[key].valid_actions;
                    obe.time = curObservation[key].time;
                    obe.scores = curObservation[key].scores;
                    this.Send(obe, 0);
                }
                if (key == 1 && blue_ok == true)
                {
                    obe.actions = curObservation[key].actions;
                    obe.cities = curObservation[key].cities;
                    obe.judge_info = curObservation[key].judge_info;
                    obe.operators = curObservation[key].operators;
                    obe.valid_actions = curObservation[key].valid_actions;
                    obe.time = curObservation[key].time;
                    obe.scores = curObservation[key].scores; //发送给蓝方
                    this.Send(obe, 1);
                }
            }
        }
        private void Send(ObservationMsg obe, int army)
        {
            string str_obe;
            str_obe = Utils.StructToJson(obe).ReadToEnd();


            if (army == 0)
            {

                Send(str_obe, IP_red);
            }
            if (army == 1)
            {
                Send(str_obe, IP_blue);
            }

        }
        private void Send(string send, List<IPEndPoint> destinations)
        {
            if (destinations == null || destinations.Count == 0)
            {
                return;
            }

            foreach (var remoteEp in destinations)
            {
                byte[] sendData = null;//要发送的字节数组 
                UdpClient client = new UdpClient();         // 有Socket，没有bind 插口绑定了IP和端口号是用来接收的
                sendData = Encoding.Default.GetBytes(send);
                //  int n=  client.Send(sendData, sendData.Length, remoteEp);//将数据发送到远程端点 
                int n = client.Send(sendData, sendData.Length, remoteEp);
                client.Close();

            }
        }
        #endregion
    }
}
